<template>
    <view class="me-tabs" :class="{ 'tabs-fixed': fixed }" :style="{ height: tabHeightVal }">
        <scroll-view v-if="tabs.length" :id="viewId" :scroll-left="scrollLeft" scroll-x scroll-with-animation :scroll-animation-duration="300">
            <view class="tabs-item" :class="{ 'tabs-flex': !isScroll, 'tabs-scroll': isScroll }">
                <!-- tab -->
                <view class="tab-item" :style="{ width: tabWidthVal, height: tabHeightVal, 'line-height': tabHeightVal }" v-for="(tab, i) in tabs" :class="{ active: modelValue === i }" :key="i" @click="tabClick(i)">
                    {{ getTabName(tab) }}
                </view>
                <!-- 下划线 -->
                <view class="tabs-line" :style="{ left: lineLeft }"></view>
            </view>
        </scroll-view>
    </view>
</template>

<script lang="ts" setup>
import { computed, ref, watch, getCurrentInstance, onMounted } from 'vue'

interface P {
    /** 支持格式: ['全部', '待付款'] 或 [{name:'全部'}, {name:'待付款'}] */
    tabs: Array<any>
    nameKey?: string
    modelValue?: string | number
    fixed?: boolean
    tabWidth?: number
    height?: number
}
const Props = withDefaults(defineProps<P>(), {
    tabs: () => [],
    nameKey: 'name', // 取name的字段
    modelValue: 0, // 当前显示的下标 (使用v-model语法糖: 1.props需为value; 2.需回调input事件)
    fixed: false, // 是否悬浮,默认false
    tabWidth: 0, // 每个tab的宽度,默认不设置值,为flex平均分配; 如果指定宽度,则不使用flex,每个tab居左,超过则水平滑动(单位默认rpx)
    height: 64 // 高度,单位rpx
})

const viewId = ref('id_' + Math.random().toString(36).substr(2, 16))
const scrollLeft = ref(0)
/** 容器宽度 */
const warpWidth = ref<number | null>(0)

const scrollTimer = ref()

const instance = getCurrentInstance()

const isScroll = computed(() => {
    return Props.tabWidth && Props.tabs.length
})

const tabHeightPx = computed(() => {
    return uni.upx2px(Props.height)
})

const tabHeightVal = computed(() => {
    return tabHeightPx.value + 'px'
})

const tabWidthPx = computed(() => {
    return uni.upx2px(Props.tabWidth)
})

const tabWidthVal = computed(() => {
    return isScroll.value ? tabWidthPx.value + 'px' : ''
})

const lineLeft = computed(() => {
    if (isScroll.value) {
        return tabWidthPx.value * Number(Props.modelValue) + tabWidthPx.value / 2 + 'px'
    } else {
        return (100 / Props.tabs.length) * (Number(Props.modelValue) + 1) - 100 / (Props.tabs.length * 2) + '%'
    }
})

watch(
    () => Props.tabs,
    async () => {
        warpWidth.value = null
        scrollCenter()
    }
)

watch(
    () => Props.height,
    () => {
        scrollCenter()
    }
)

const scrollCenter = async () => {
    if (!isScroll.value) return
    if (!warpWidth.value) {
        // tabs容器的宽度
        let rect: any = await initWarpRect()
        warpWidth.value = rect ? rect.width : uni.getSystemInfoSync().windowWidth // 某些情况下取不到宽度,暂时取屏幕宽度
    }
    let tabLeft = tabWidthPx.value * Number(Props.modelValue) + tabWidthPx.value / 2 // 当前tab中心点到左边的距离
    let diff = tabLeft - (warpWidth.value || 0) / 2 // 如果超过tabs容器的一半,则滚动差值
    scrollLeft.value = diff
    // #ifdef MP-TOUTIAO
    scrollTimer.value && clearTimeout(scrollTimer.value)
    scrollTimer.value = setTimeout(() => {
        // 字节跳动小程序,需延时再次设置scrollLeft,否则tab切换跨度较大时不生效
        scrollLeft.value = Math.ceil(diff)
    }, 400)
    // #endif
}

const getTabName = (tab: any) => {
    return typeof tab === 'object' ? tab[Props.nameKey] : tab
}

const initWarpRect = () => {
    return new Promise(resolve => {
        setTimeout(() => {
            // 延时确保dom已渲染, 不使用$nextclick
            let query = uni.createSelectorQuery()
            // #ifndef MP-ALIPAY
            query = query.in(instance) // 支付宝小程序不支持in(this),而字节跳动小程序必须写in(this), 否则都取不到值
            // #endif
            query
                .select('#' + viewId.value)
                .boundingClientRect(data => {
                    resolve(data)
                })
                .exec()
        }, 20)
    })
}
const emit = defineEmits(['update:modelValue', 'change'])

const tabClick = (i: number) => {
    console.log('目标:', i);
    console.log('当前页:', Props.modelValue );
    if (Props.modelValue != i) {
        emit('update:modelValue', i)
        emit('change', i)
    }
}

onMounted(() => {
    scrollCenter()
})
</script>

<style scoped lang="scss">
.me-tabs {
    position: relative;
    font-size: 32rpx;
    background-color: #fff;
    // border-bottom: 1rpx solid #eee;
    box-sizing: border-box;
    overflow-y: hidden;
    background-color: #fff;
    &.tabs-fixed {
        z-index: 990;
        position: fixed;
        top: var(--window-top);
        left: 0;
        width: 100%;
    }

    .tabs-item {
        position: relative;
        white-space: nowrap;
        padding-bottom: 30rpx; // 撑开高度,再配合me-tabs的overflow-y: hidden,以达到隐藏滚动条的目的
        box-sizing: border-box;
        .tab-item {
            position: relative;
            text-align: center;
            box-sizing: border-box;
            &.active {
                color: #fc4f75;
                // font-weight: 600;
                font-weight: bolder;
                font-size: 32rpx;
            }
        }
    }

    // 平分的方式显示item
    .tabs-flex {
        display: flex;
        .tab-item {
            flex: 1;
        }
    }
    // 居左显示item,支持水平滑动
    .tabs-scroll {
        .tab-item {
            display: inline-block;
        }
    }

    // 选中tab的线
    .tabs-line {
        z-index: 1;
        position: absolute;
        bottom: 30rpx; // 至少与.tabs-item的padding-bottom一致,才能保证在底部边缘
        width: 50rpx;
        height: 6rpx;
        transform: translateX(-50%);
        border-radius: 4rpx;
        transition: left 0.3s;
        background: #fc4f75;
    }
}
</style>
